package cn.cosmosx.base.encrypt.sm;

import cn.cosmosx.base.encrypt.hex.HexUtil;
import cn.cosmosx.base.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.analysis.function.Sin;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECFieldFp;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.EllipticCurve;
import java.util.HashMap;
import java.util.Map;

/**
 * SM2工具类
 * <p>
 * 包含加解密及签名
 * <p>
 * 加密及签名步骤：
 * （1）公钥加密（提供方1）：SM2公钥加密得到密文{@linkplain SM2Util#encrypt(String, String)}
 * <p>
 * （2）私钥签名（提供方2）：使用SM2 私钥对 密文进行签名，得到签名值{@linkplain SM2Util#sign(String, String)}
 * <p>
 * （3）公钥验签（提供方2）：使用SM2 公钥、密文、签名值 进行验签{@linkplain SM2Util#verify(String, String, String)}
 * <p>
 * （4）私钥解密（提供方1）：使用SM2 私钥进行解密得到明文{@linkplain SM2Util#decrypt(String, String)}
 * <p>
 * 注：加解密和签名验签的公私钥均为SM2非对称秘钥对，。但可能同一对秘钥对
 *
 * @author gengzhy
 */
@Slf4j
public class SM2Util {
    private final static Charset CHARSET = StandardCharsets.UTF_8;
    private static final BouncyCastleProvider PROVIDER = Provider.INSTANCE.getProvider();
    // 签名ID，初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
    private final static String SIGN_ID = "5022100d41c85325c0c7e637c75276df360dee1862c94e07073ace9c742bd25e0e432b902205706ec3c4ac11147fd6eb6a308";

    // 默认的公私钥对
    private final static String PUB_KEY = "04d66c2787e2856c53833d619c5920b727824f5501ca59b78828d3de8ca170e251ef606b5aa79295e185d0fc4b4939e13912b3902fcf4b1c93ea81748fdf76d573";
    private final static String PRI_KEY = "00df314a482110461e8773e482c01804bb5552d52b7efc6729f2560a8e085e3aa3";

    /**
     * sm2 加密
     *
     * @param content 内容
     * @return 密文
     */
    public static String encrypt(String content) {
        return encrypt(PUB_KEY, content);
    }

    /**
     * sm2 加密
     *
     * @param publicKey 公钥
     * @param content   内容
     * @return 密文
     */
    public static String encrypt(String publicKey, String content) {
        return encrypt(publicKey, content.getBytes());
    }

    /**
     * sm2 加密
     *
     * @param publicKey 公钥
     * @param content   内容
     * @return 密文
     */
    public static String encrypt(String publicKey, byte[] content) {
        String contentEncrypt = StringUtils.EMPTY;
        try {
            // 获取SM2相关参数
            X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
            // 椭圆曲线参数规格
            ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
            // 将公钥HEX字符串转换为椭圆曲线对应的点
            ECPoint ecPoint = parameters.getCurve().decodePoint(HexUtil.decodeStrict(publicKey));
            // 获取椭圆曲线KEY生成器
            KeyFactory keyFactory = KeyFactory.getInstance("EC", PROVIDER);
            // 将椭圆曲线点转为公钥KEY对象
            BCECPublicKey bcecPublicKey = (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));

            // 获取SM2加密器
            Cipher cipher = Cipher.getInstance("SM2", PROVIDER);
            // 初始化为加密模式
            cipher.init(Cipher.ENCRYPT_MODE, bcecPublicKey);
            // 转Hex String
            contentEncrypt = HexUtil.toHexString(cipher.doFinal(content));
        } catch (Exception e) {
            log.error("SM2 encrypt error", e);
        }
        return contentEncrypt;
    }

    /**
     * sm2 加密
     *
     * @param contentDecrypt 密文
     * @return 明文
     */
    public static String decrypt(String contentDecrypt) {
        return decrypt(PRI_KEY, contentDecrypt);
    }

    /**
     * sm2 加密
     *
     * @param privateKey     私钥
     * @param contentDecrypt 密文
     * @return 明文
     */
    public static String decrypt(String privateKey, String contentDecrypt) {
        return decrypt(privateKey, contentDecrypt.getBytes());
    }

    /**
     * sm2 解密
     *
     * @param privateKey     私钥
     * @param contentDecrypt 密文
     * @return 明文
     */
    public static String decrypt(String privateKey, byte[] contentDecrypt) {
        String content;
        try {
            // 获取SM2相关参数
            X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
            // 椭圆曲线参数规格
            ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
            // 将私钥HEX字符串转换为X值
            BigInteger bigInteger = new BigInteger(HexUtil.decodeStrict(privateKey));
            // 获取椭圆曲线KEY生成器
            KeyFactory keyFactory = KeyFactory.getInstance("EC", PROVIDER);
            // 将X值转为私钥KEY对象
            BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger, ecParameterSpec));

            // 获取SM2加密器
            Cipher cipher = Cipher.getInstance("SM2", PROVIDER);
            // 初始化为加密模式
            cipher.init(Cipher.DECRYPT_MODE, bcecPrivateKey);
            // 解密
            byte[] decode = HexUtil.decode(contentDecrypt);
            content = new String(cipher.doFinal(decode), CHARSET);
        } catch (Exception e) {
            log.error("SM2解密失败", e);
            throw new BusinessException("解密失败:" + e.getMessage());
        }
        return content;
    }

    /**
     * 私钥签名
     *
     * @param privateKey 私钥
     * @param content    待签名内容
     * @return - 签名值
     */
    public static String sign(String privateKey, String content) throws CryptoException {
        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(HexUtil.decodeStrict(privateKey));
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();

        //初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
        try {
            sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters,
                    SecureRandom.getInstance("SHA1PRNG")),
                    Strings.toByteArray(SIGN_ID)));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.info(e.getMessage());
        }
        byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
        sm2Signer.update(bytes, 0, bytes.length);
        //生成签名,签名分为两部分r和s,分别对应索引0和1的数组
        byte[] signBytes = sm2Signer.generateSignature();
        return HexUtil.toHexString(signBytes);
    }

    /**
     * 验证签名
     *
     * @param publicKey 公钥
     * @param content   签名内容（SM公钥加密）
     * @param sign      签名值
     * @return - boolean
     */
    public static boolean verify(String publicKey, String content, String sign) {
        //待签名内容
        byte[] message = content.getBytes(StandardCharsets.UTF_8);
        byte[] signData = HexUtil.decodeStrict(sign);

        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(HexUtil.decodeStrict(publicKey));
        // 公钥前面的02或者03表示是压缩公钥，04表示未压缩公钥, 04的时候，可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();
        sm2Signer.init(false, new ParametersWithID(publicKeyParameters, Strings.toByteArray(SIGN_ID)));
        sm2Signer.update(message, 0, message.length);
        //验证签名结果
        return sm2Signer.verifySignature(signData);
    }

    /**
     * SM2 生成公私钥
     *
     * @return 公私钥
     */
    public static Map<KeyType, String> generateKeyPair() {
        try {
            Map<KeyType, String> resultMap = new HashMap<>(2);
            // 获取椭圆曲线相关生成参数规格
            ECGenParameterSpec genParameterSpec = new ECGenParameterSpec("sm2p256v1");
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", PROVIDER);
            // 使用SM2的算法区域初始化密钥生成器
            keyPairGenerator.initialize(genParameterSpec, new SecureRandom());
            // 生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 私钥
            BCECPrivateKey exPrivateKey = (BCECPrivateKey) keyPair.getPrivate();
            // 公钥
            BCECPublicKey ecPublicKey = (BCECPublicKey) keyPair.getPublic();
            resultMap.put(KeyType.PRIVATE_KEY, HexUtil.toHexString(exPrivateKey.getD().toByteArray()));
            resultMap.put(KeyType.PUBLIC_KEY, HexUtil.toHexString(ecPublicKey.getQ().getEncoded(false)));// 非压缩
            return resultMap;
        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
            log.info("NoSuchAlgorithmException | InvalidAlgorithmParameterException", e);
            throw new RuntimeException("SM2 KeyPair generate failed.");
        }
    }

    public static void main(String[] args) throws CryptoException {
        while (true) {
            test();
        }
    }
    static void test() throws CryptoException {
        Map<KeyType, String> map = generateKeyPair();
        System.out.println(map);
        String pubKey = map.get(KeyType.PUBLIC_KEY);
        String priKey = map.get(KeyType.PRIVATE_KEY);
        String msg = "你好世界！";
        String encrypt = encrypt(pubKey, msg);
        System.out.println("encrypt = " + encrypt);
        String decrypt = decrypt(priKey, encrypt);
        System.out.println("decrypt = " + decrypt);
        String sign = sign(priKey, msg);
        System.out.println("sign = " + sign);
        boolean verify = verify(pubKey, msg, sign);
        System.out.println("verify = " + verify);
        getPrivateKeyObject(priKey);
        getPublicKeyObject(pubKey);
    }

    //######################以下不常用############################

    /**
     * 根据 16进制文本私钥获取私钥对象
     *
     * @param priKey - 16进制私钥
     */
    public static ECPrivateKeyParameters getPrivateKeyObject(String priKey) {
        return new ECPrivateKeyParameters(new BigInteger(ByteUtils.fromHexString(priKey)), SM2Util.BaseSM2.DOMAIN_PARAMS);
    }

    /**
     * 根据 16进制文本公钥获取密钥对象
     *
     * @param pubKey - 16进制文本公钥
     */
    public static ECPublicKeyParameters getPublicKeyObject(String pubKey) {
        String publicKeyX = pubKey.substring(2, 66);
        String publicKeyY = pubKey.substring(66);
        return BCECUtil.createECPublicKeyParameters(publicKeyX, publicKeyY, SM2Util.BaseSM2.CURVE, SM2Util.BaseSM2.DOMAIN_PARAMS);
    }

    /**
     * 加密
     *
     * @param pubKeyParameters 公钥
     * @param srcData          原文
     * @return 默认输出C1C3C2顺序的密文。C1为65字节第1字节为压缩标识，这里固定为0x04，后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
     */
    public static byte[] encrypt(ECPublicKeyParameters pubKeyParameters, byte[] srcData) throws InvalidCipherTextException {
        return encrypt(SM2Engine.Mode.C1C3C2, pubKeyParameters, srcData);
    }

    /**
     * 加密
     *
     * @param mode             指定密文结构，旧标准的为C1C2C3，新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
     * @param pubKeyParameters 公钥
     * @param srcData          原文
     * @return 根据mode不同，输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识，这里固定为0x04，后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
     */
    public static byte[] encrypt(SM2Engine.Mode mode, ECPublicKeyParameters pubKeyParameters, byte[] srcData) throws InvalidCipherTextException {
        SM2Engine engine = new SM2Engine(mode);
        ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParameters, new SecureRandom());
        engine.init(true, pwr);
        return engine.processBlock(srcData, 0, srcData.length);
    }

    /**
     * 解密
     *
     * @param priKeyParameters 私钥
     * @param sm2Cipher        默认输入C1C3C2顺序的密文。C1为65字节第1字节为压缩标识，这里固定为0x04，后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
     * @return 原文。SM2解密返回了数据则一定是原文，因为SM2自带校验，如果密文被篡改或者密钥对不上，都是会直接报异常的。
     */
    public static byte[] decrypt(ECPrivateKeyParameters priKeyParameters, byte[] sm2Cipher) throws InvalidCipherTextException {
        return decrypt(SM2Engine.Mode.C1C3C2, priKeyParameters, sm2Cipher);
    }

    /**
     * 解密
     *
     * @param mode             指定密文结构，旧标准的为C1C2C3，新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
     * @param priKeyParameters 私钥
     * @param sm2Cipher        根据mode不同，需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识，这里固定为0x04，后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
     * @return 原文。SM2解密返回了数据则一定是原文，因为SM2自带校验，如果密文被篡改或者密钥对不上，都是会直接报异常的。
     */
    public static byte[] decrypt(SM2Engine.Mode mode, ECPrivateKeyParameters priKeyParameters, byte[] sm2Cipher) throws InvalidCipherTextException {
        SM2Engine engine = new SM2Engine(mode);
        engine.init(false, priKeyParameters);
        return engine.processBlock(sm2Cipher, 0, sm2Cipher.length);
    }

    //###############################签名/验签##########################

    /**
     * 私钥签名
     *
     * @param priKey  私钥
     * @param srcData 原文
     * @return DER编码后的签名值
     */
    public static byte[] sign(BCECPrivateKey priKey, byte[] srcData) throws CryptoException {
        ECPrivateKeyParameters priKeyParameters = BCECUtil.convertPrivateKeyToParameters(priKey);
        return sign(priKeyParameters, null, srcData);
    }

    /**
     * 私钥签名
     * 不指定withId，则默认withId为字节数组:"1234567812345678".getBytes()
     *
     * @param priKeyParameters 私钥
     * @param srcData          原文
     * @return DER编码后的签名值
     */
    public static byte[] sign(ECPrivateKeyParameters priKeyParameters, byte[] srcData) throws CryptoException {
        return sign(priKeyParameters, null, srcData);
    }

    /**
     * 私钥签名
     *
     * @param priKey  私钥
     * @param withId  可以为null，若为null，则默认withId为字节数组:"1234567812345678".getBytes()
     * @param srcData 原文
     * @return DER编码后的签名值
     */
    public static byte[] sign(BCECPrivateKey priKey, byte[] withId, byte[] srcData) throws CryptoException {
        ECPrivateKeyParameters priKeyParameters = BCECUtil.convertPrivateKeyToParameters(priKey);
        return sign(priKeyParameters, withId, srcData);
    }

    /**
     * 私钥签名
     *
     * @param priKeyParameters 私钥
     * @param withId           可以为null，若为null，则默认withId为字节数组:"1234567812345678".getBytes()
     * @param srcData          源数据
     * @return DER编码后的签名值
     */
    public static byte[] sign(ECPrivateKeyParameters priKeyParameters, byte[] withId, byte[] srcData) throws CryptoException {
        SM2Signer signer = new SM2Signer();
        CipherParameters param;
        ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom());
        if (withId != null) {
            param = new ParametersWithID(pwr, withId);
        } else {
            param = pwr;
        }
        signer.init(true, param);
        signer.update(srcData, 0, srcData.length);
        return signer.generateSignature();
    }

    /**
     * 公钥验签
     *
     * @param pubKey  公钥
     * @param srcData 原文
     * @param sign    DER编码的签名值
     * @return 验签成功返回true，失败返回false
     */
    public static boolean verify(BCECPublicKey pubKey, byte[] srcData, byte[] sign) {
        ECPublicKeyParameters pubKeyParameters = BCECUtil.convertPublicKeyToParameters(pubKey);
        return verify(pubKeyParameters, null, srcData, sign);
    }

    /**
     * 公钥验签
     * 不指定withId，则默认withId为字节数组:"1234567812345678".getBytes()
     *
     * @param pubKeyParameters 公钥
     * @param srcData          原文
     * @param sign             DER编码的签名值
     * @return 验签成功返回true，失败返回false
     */
    public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] srcData, byte[] sign) {
        return verify(pubKeyParameters, null, srcData, sign);
    }

    /**
     * 公钥验签
     *
     * @param pubKey  公钥
     * @param withId  可以为null，若为null，则默认withId为字节数组:"1234567812345678".getBytes()
     * @param srcData 原文
     * @param sign    DER编码的签名值
     * @return 验签成功返回true，失败返回false
     */
    public static boolean verify(BCECPublicKey pubKey, byte[] withId, byte[] srcData, byte[] sign) {
        ECPublicKeyParameters pubKeyParameters = BCECUtil.convertPublicKeyToParameters(pubKey);
        return verify(pubKeyParameters, withId, srcData, sign);
    }

    /**
     * 公钥验签
     *
     * @param pubKeyParameters 公钥
     * @param withId           可以为null，若为null，则默认withId为字节数组:"1234567812345678".getBytes()
     * @param srcData          原文
     * @param sign             DER编码的签名值
     * @return 验签成功返回true，失败返回false
     */
    public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] withId, byte[] srcData, byte[] sign) {
        SM2Signer signer = new SM2Signer();
        CipherParameters param;
        if (withId != null) {
            param = new ParametersWithID(pubKeyParameters, withId);
        } else {
            param = pubKeyParameters;
        }
        signer.init(false, param);
        signer.update(srcData, 0, srcData.length);
        return signer.verifySignature(sign);
    }

    /**
     * 将DER编码的SM2签名解码成64字节的纯R+S字节流
     *
     * @param derSign - DER编码的SM2签名
     * @return 64字节数组，前32字节为R，后32字节为S
     */
    public static byte[] decodeDERSM2Sign(byte[] derSign) {
        ASN1Sequence as = DERSequence.getInstance(derSign);
        byte[] rBytes = ((ASN1Integer) as.getObjectAt(0)).getValue().toByteArray();
        byte[] sBytes = ((ASN1Integer) as.getObjectAt(1)).getValue().toByteArray();
        //由于大数的补0规则，所以可能会出现33个字节的情况，要修正回32个字节
        rBytes = fixToCurveLengthBytes(rBytes);
        sBytes = fixToCurveLengthBytes(sBytes);
        byte[] rawSign = new byte[rBytes.length + sBytes.length];
        System.arraycopy(rBytes, 0, rawSign, 0, rBytes.length);
        System.arraycopy(sBytes, 0, rawSign, rBytes.length, sBytes.length);
        return rawSign;
    }

    /**
     * 把64字节的纯R+S字节数组编码成DER编码
     *
     * @param rawSign 64字节数组形式的SM2签名值，前32字节为R，后32字节为S
     * @return DER编码后的SM2签名值
     */
    public static byte[] encodeSM2SignToDER(byte[] rawSign) throws IOException {
        //要保证大数是正数
        BigInteger r = new BigInteger(1, extractBytes(rawSign, 0, 32));
        BigInteger s = new BigInteger(1, extractBytes(rawSign, 32, 32));
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(r));
        v.add(new ASN1Integer(s));
        return new DERSequence(v).getEncoded(ASN1Encoding.DER);
    }

    private static byte[] extractBytes(byte[] src, int offset, int length) {
        byte[] result = new byte[length];
        System.arraycopy(src, offset, result, 0, result.length);
        return result;
    }

    private static byte[] fixToCurveLengthBytes(byte[] src) {
        if (src.length == BaseSM2.CURVE_LEN) {
            return src;
        }
        byte[] result = new byte[BaseSM2.CURVE_LEN];
        if (src.length > BaseSM2.CURVE_LEN) {
            System.arraycopy(src, src.length - result.length, result, 0, result.length);
        } else {
            System.arraycopy(src, 0, result, result.length - src.length, src.length);
        }
        return result;
    }

    /**
     * SM2推荐曲线参数配置
     */
    static class BaseSM2 {
        public final static SM2P256V1Curve CURVE = new SM2P256V1Curve();
        public final static BigInteger SM2_ECC_P = CURVE.getQ();
        public final static BigInteger SM2_ECC_A = CURVE.getA().toBigInteger();
        public final static BigInteger SM2_ECC_B = CURVE.getB().toBigInteger();
        public final static BigInteger SM2_ECC_N = CURVE.getOrder();
        public final static BigInteger SM2_ECC_H = CURVE.getCofactor();
        public final static BigInteger SM2_ECC_GX = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
        public final static BigInteger SM2_ECC_GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
        public final static ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
        public final static ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT, SM2_ECC_N, SM2_ECC_H);
        public final static int CURVE_LEN = BCECUtil.getCurveLength(DOMAIN_PARAMS);
        //////////////////////////////////////////////////////////////////////////////////////

        public final static EllipticCurve JDK_CURVE = new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B);
        public final static java.security.spec.ECPoint JDK_G_POINT = new java.security.spec.ECPoint(G_POINT.getAffineXCoord().toBigInteger(), G_POINT.getAffineYCoord().toBigInteger());
        public final static java.security.spec.ECParameterSpec JDK_EC_SPEC = new java.security.spec.ECParameterSpec(JDK_CURVE, JDK_G_POINT, SM2_ECC_N, SM2_ECC_H.intValue());

        //////////////////////////////////////////////////////////////////////////////////////
        public final static int SM3_DIGEST_LENGTH = 32;
    }

}